//modified from boost::any
#pragma once
#include "../common.hpp"
#include "Uncopyable.hpp"
#ifdef __GNUC__
#include <typeinfo>
#endif

namespace zzz{
//Any is NOT a template class
class Any {
public:
  // Empty construct
  Any():content_(0){}
  // Construct from T
  template<typename T>
  Any(const T & value):content_(new Holder<T>(value)){}
  // Copy construct, will reproduce a item
  // Attention that it is not template, no Type is required
  Any(const Any & other):content_(other.content_?other.content_->Clone():0){}
  ~Any(){delete content_;}
public:
  // Copy from value
  template<typename T>
  const Any& operator=(const T & other) {
    if (content_) delete content_;
    content_=new Holder<T>(other);
    return *this;
  }

  // Copy from other Any
  const Any& operator=(const Any &other) {
    if (content_) delete content_;
    content_=other.content_->Clone();
    return *this;
  }

  bool Empty() const {
    return !content_;
  }

  const std::type_info& Type() const {
    return content_ ? content_->Type() : typeid(void);
  }

  template<typename T>
  inline bool IsType() {
    return content_->Type() == typeid(T);
  }

private: // types
  class PlaceHolder {
  public:
    virtual ~PlaceHolder(){}
    virtual const std::type_info & Type() const = 0;
    virtual PlaceHolder * Clone() const = 0;
  };

  template<typename T>
  class Holder : public PlaceHolder, Uncopyable {
  public:
    Holder(const T & value):v(value){}
    virtual const std::type_info & Type() const{return typeid(T);}
    //for operator= for Any
    virtual PlaceHolder * Clone() const{return new Holder(v);}
    T v;
  };
  PlaceHolder* content_;

  template<typename T>
  friend inline T& any_cast(Any* operand);
  template<typename T>
  friend inline const T& any_cast(const Any* operand);
  template<typename T>
  friend inline T& unsafe_any_cast(Any* operand);
  template<typename T>
  friend inline const T& unsafe_any_cast(const Any* operand);
  template<typename T>
  friend inline T& any_cast(Any& operand);
  template<typename T>
  friend inline const T& any_cast(const Any& operand);
};
///cast//////////////////////////////////////////////////////////////////////////
class bad_any_cast : public std::bad_cast {
public:
  virtual const char *what() const throw() {
    return "zzz::bad_any_cast: failed conversion using zzz::any_cast";
  }
};

//Any* -> T&
template<typename T>
inline T& any_cast(Any* operand) {
  if (operand==NULL || operand->Type() != typeid(T))
    throw bad_any_cast();
  return static_cast<Any::Holder<T> *>(operand->content_)->v;
}

//const Any* -> const T&
template<typename T>
inline const T& any_cast(const Any* operand) {
  if (operand==NULL || operand->Type() != typeid(T))
    throw bad_any_cast();
  return static_cast<Any::Holder<T> *>(operand->content_)->v;
}

//Any* -> T&
template<typename T>
inline T& unsafe_any_cast(Any* operand) {
  return static_cast<Any::Holder<T> *>(operand->content_)->v;
}

//const Any* -> const T&
template<typename T>
inline const T& unsafe_any_cast(const Any* operand) {
  return static_cast<Any::Holder<T> *>(operand->content_)->v;
}

//Any& -> T&
template<typename T>
inline T& any_cast(Any& operand) {
  if (operand.Type() != typeid(T)) 
    throw bad_any_cast();
  return static_cast<Any::Holder<T> *>(operand.content_)->v;
}

//const Any& -> const T&
template<typename T>
inline const T& any_cast(const Any& operand) {
  if (operand.Type() != typeid(T))
    throw bad_any_cast();
  return static_cast<Any::Holder<T> *>(operand.content_)->v;
}

}  // namespace zzz
